package com.iflyings.android.dataconfig

import android.content.ContentProvider
import android.content.ContentValues
import android.content.UriMatcher
import android.content.pm.PackageManager
import android.database.Cursor
import android.net.Uri
import android.os.Environment
import android.util.Log
import java.io.File

internal class ConfigContentProvider: ContentProvider() {

    private val mUriMatcher = UriMatcher(UriMatcher.NO_MATCH)

    companion object {
        private const val TAG = "ConfigContentProvider"
        private const val MATCH_ALL = 100
        private const val MATCH_ITEM = 101
        const val TABLE_NAME = "config"

        private lateinit var mAuthProvider: String

        fun getNotifyUri(tableName: String): Uri = Uri.parse("content://$mAuthProvider/$tableName")
    }

    override fun onCreate(): Boolean {
        mAuthProvider = context!!.packageName + ".dataconfig.configProvider"

        mUriMatcher.addURI(mAuthProvider, "$TABLE_NAME/*", MATCH_ITEM)
        mUriMatcher.addURI(mAuthProvider, TABLE_NAME, MATCH_ALL)

        var dirPath: String? = null
        try {
            val packageManager = context!!.packageManager
            val applicationInfo = packageManager.getApplicationInfo(context!!.packageName, PackageManager.GET_META_DATA)
            if (applicationInfo.metaData != null) {
                dirPath = applicationInfo.metaData.getString("CONFIG_DATA_PATH")
            }
        } catch (_: PackageManager.NameNotFoundException) {}

        if (!dirPath.isNullOrEmpty()) {
            val configFile =  if (dirPath.startsWith("/")) {
                File(dirPath)
            } else {
                File(context!!.filesDir, dirPath)
            }
            if (configFile.absolutePath.startsWith(Environment.getExternalStorageDirectory().absolutePath)) {
                if (!Environment.getExternalStorageDirectory().exists()) {
                    Log.i(TAG, "ConfigContentProvider::loadData: $configFile error")
                    return true
                }
            }

            Log.i(TAG, "ConfigContentProvider::loadData: $configFile success")
            IniSection.init(configFile.absolutePath)
        }

        return true
    }

    override fun shutdown() {
        Log.i(TAG, "ConfigContentProvider::shutdown")
        super.shutdown()
    }

    override fun query(uri: Uri, projection: Array<out String>?,
                       selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): Cursor? {
        when (mUriMatcher.match(uri)) {
            MATCH_ALL -> return IniSection.get().getAllData()
            else -> {
                val list = uri.pathSegments
                when (list.size) {
                    0 -> return IniSection.get().getAllData()
                    1 -> return IniSection.get().getAllData(list[0])
                    2 -> return IniSection.get().getItemData(list[0], list[1])
                    else -> {}
                }
            }
        }
        Log.e(TAG, "query Uri error: $uri")
        return null
    }

    override fun insert(uri: Uri, values: ContentValues?): Uri? {
        val contentResolver = context?.contentResolver ?: return null
        val data = getInfoFromUri(uri, values) ?: return null
        IniSection.setValue(data.first, data.second, data.third)
        val notifyUri = Uri.withAppendedPath(getNotifyUri(TABLE_NAME), data.second)
        contentResolver.notifyChange(notifyUri, null)
        return notifyUri
    }

    override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<out String>?): Int {
        val contentResolver = context?.contentResolver ?: return 0
        val data = getInfoFromUri(uri, values) ?: return 0
        IniSection.setValue(data.first, data.second, data.third)
        val notifyUri = Uri.withAppendedPath(getNotifyUri(TABLE_NAME), data.second)
        contentResolver.notifyChange(notifyUri, null)
        return 1
    }

    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
        val list = uri.pathSegments
        if (list.size == 1) {
            IniSection.remove(list[0])
            return 1
        } else if (list.size == 2) {
            IniSection.remove(list[0], list[1])
            return 1
        }
        Log.e(TAG, "delete Uri error: $uri")
        return 0
    }

    override fun getType(uri: Uri): String {
        return when (mUriMatcher.match(uri)) {
            MATCH_ALL -> "vnd.android.cursor.dir/data"
            MATCH_ITEM -> "vnd.android.cursor.item/data"
            else -> throw IllegalArgumentException("Unknown URI: $uri")
        }
    }

    private fun getInfoFromUri(uri: Uri, values: ContentValues?): Triple<String, String, String>? {
        val list = uri.pathSegments
        var section: String? = ""
        var name: String? = ""
        var value: String? = ""
        if (list.size == 1 && values != null) {
            section = list[0]
            name = values.getAsString(IniSection.NAME)
            value = values.getAsString(IniSection.VALUE)
        } else if (list.size == 2 && values != null) {
            section = list[0]
            name = list[1]
            value = values.getAsString(IniSection.VALUE)
        } else if (list.size == 3) {
            section = list[0]
            name = list[1]
            value = list[2]
        }
        if (section.isNullOrEmpty() || name.isNullOrEmpty() || value.isNullOrEmpty()) {
            Log.e(TAG, "getInfoFromUri Uri error: $uri")
            return null
        }
        return Triple(section, name, value)
    }
}
